package apps

import (
	"context"
	"gitee.com/captials-team/ubdframe/src/common"
	"gitee.com/captials-team/ubdframe/src/domain/interfaces"
	"gitee.com/captials-team/ubdframe/src/pkg/comag"
	v1log "gitee.com/captials-team/ubdframe/src/pkg/logs"
	"go.uber.org/dig"
	"os"
	"os/signal"
	"syscall"
)

type AppManager struct {
	di     *dig.Container
	apps   []interfaces.ItfApp
	logger v1log.ILog

	process *comag.ConProcessModelActuator
}

func (mgr *AppManager) WithApp(app interfaces.ItfApp) {
	mgr.apps = append(mgr.apps, app)
}

// Start 启动，启动所有application，会阻塞直到有退出问题
func (mgr *AppManager) Start() error {
	//准备启动事宜
	for _, v := range mgr.apps {
		var ap = v

		mgr.process.Add(func(ctx context.Context) {
			defer mgr.logger.Info("%s STOP SUCCESS", ap.Name())

			//异步启动
			go func() {
				mgr.logger.Info("%s START...", ap.Name())
				if err := ap.Start(); err != nil {
					//一个失败停止全部
					mgr.logger.Warn("%s START FAIL..%s", ap.Name(), err)
					mgr.process.Stop()
					return
				}
			}()

			//之后监听停止context
			for {
				select {
				case <-ctx.Done():
					mgr.logger.Warn("%s STOPPING...", ap.Name())
					common.ErrPanic(ap.Stop())
					return
				}
			}
		})
	}

	//启动
	if err := mgr.process.Start(); err != nil {
		return err
	}

	return mgr.process.Wait()
}

func (mgr *AppManager) Stop() error {
	defer mgr.logger.Warn("EXIT DONE")

	if err := mgr.process.Stop(); err != nil {
		return err
	}
	return mgr.process.Wait()
}

// WithSignalExit 收到系统信号后退出所有app
func (mgr *AppManager) WithSignalExit(signs ...os.Signal) {
	sigCh := make(chan os.Signal)
	if len(signs) == 0 {
		signs = append(signs,
			syscall.SIGINT,
			syscall.SIGTERM,
			syscall.SIGQUIT,
			syscall.SIGHUP,
			syscall.SIGABRT,
		)
	}
	signal.Notify(sigCh, signs...)
	go func() {
		for {
			select {
			case sig := <-sigCh:
				mgr.logger.Warn("RECEIVE SIGNAL EXIT %s", sig.String())
				common.ErrPanic(mgr.Stop())
				return
			}
		}
	}()
}

func NewAppManager(di *dig.Container, logger v1log.ILog) *AppManager {
	return &AppManager{
		di:      di,
		logger:  logger,
		process: comag.NewConProcessModelActuator(),
	}
}
